﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MagicArena.framework.component;
using MagicArena.framework.state;
using MagicArena.framework.physics;
using MagicArena.framework.graphics;
using Microsoft.Xna.Framework;
using MagicArena.framework.logic;
using MagicArena.framework.action;

namespace MagicArena.framework.toon
{
    public abstract class Toon : IUpdateable, IPositionState
    {
        #region Properties
        private ARenderer _Rend;
        protected ARenderer Rend
        {
            get { return _Rend; }
            set
            {
                value.AttachToToon(this);
                _Rend = value;
            }
        }
        private AVisionController _Vision;
        protected AVisionController Vision
        {
            get { return _Vision; }
            set
            {
                value.AttachToToon(this);
                _Vision = value;
            }
        }
        protected List<State> _States = new List<State>(10);
        public State[] States
        {
            get
            {
                return _States.ToArray();
            }
        }
        public AAction[] Actions
        {
            get;
            protected set;
        }
        public string Name
        {
            get;
            protected set;
        }
        private ACollider _Collider;
        protected ACollider Collider
        {
            get { return _Collider; }
            set
            {
                value.AttachToToon(this);
                _Collider = value;
            }
        }
        private AToonLogic _Logic;
        protected AToonLogic Logic
        {
            get { return _Logic; }
            set
            {
                value.AttachToToon(this);
                _Logic = value;
            }
        }
        #endregion

        public Toon(string name)
        {
            Name = name;
        }

        public Toon(ARenderer r, AVisionController v, State[] ss, AAction[] a, string name, ACollider c)
        {
            Rend = r;
            Vision = v;
            _States.AddRange(ss);
            Actions = a;
            Name = name;
            Collider = c;

            if (State.FindById(ss, State.Common.Xpos) == null)
                _States.Add(new State(State.Common.Xpos, 0));
            if (State.FindById(ss, State.Common.Ypos) == null)
                _States.Add(new State(State.Common.Ypos, 0));

        }

        #region Abstract Methods
        #endregion

        #region IUpdatable methods
        #region Enabled
        private bool _Enabled = false;
        public bool Enabled
        {
            get { return _Enabled; }
            set
            {
                if (_Enabled != value)
                {
                    _Enabled = value;
                    OnEnabledChanged(new EnabledEventArgs(value));
                }
                _Enabled = value;
                SetComponentEnable(value);
            }
        }

        private void SetComponentEnable(bool value)
        {
            _Vision.Enabled = value;
            _Logic.Enabled = value;
            _Rend.Enabled = value;
            
        }
        public event EventHandler<EventArgs> EnabledChanged;
        public class EnabledEventArgs : EventArgs
        {
            public bool NewState
            {
                get;
                private set;
            }
            public EnabledEventArgs(bool state)
            {
                NewState = state;
            }
        }
        protected virtual void OnEnabledChanged(EventArgs e)
        {
            if (EnabledChanged != null) EnabledChanged(this, e);
        }
        #endregion

        #region Update
        public virtual void Update(GameTime gameTime)
        {
            // Update components
            updateComponent(_Vision, gameTime);
            updateComponent(_Logic, gameTime);
            updateComponent(_Rend, gameTime);
            foreach (AAction a in Actions)
            {
                updateComponent(a, gameTime);
            }

            // Get and execute next action
            
        }
        private void updateComponent(IUpdateable c, GameTime g)
        {
            if (c.Enabled) c.Update(g);
        }
        
        private int _UpdateOrder=int.MaxValue/2;
        public int UpdateOrder
        {
            //TODO figure out a logical update order
            get { return _UpdateOrder; }
            protected set 
            {
                if (_UpdateOrder != value)
                {
                    _UpdateOrder = value;
                    OnUpdateOrderChanged(new UpdateOrderEventArgs(value));
                }
                _UpdateOrder = value; 
            }
        }

        public event EventHandler<EventArgs> UpdateOrderChanged;
        protected virtual void OnUpdateOrderChanged(UpdateOrderEventArgs e)
        {
            if(UpdateOrderChanged != null) UpdateOrderChanged(this, e);
        }
        public class UpdateOrderEventArgs : EventArgs
        {
            public int NewValue
            {
                get;
                private set;
            }
            public UpdateOrderEventArgs(int val)
            {
                NewValue = val;
            }
        }
        #endregion
        #endregion

        #region IPositionState methods
        public State GetXPos()
        {
            return State.FindById(States, State.Common.Xpos);
        }

        public State GetYPos()
        {
            return State.FindById(States, State.Common.Ypos);
        }
        #endregion
    }
}